/**
  ETFRoot project, Anyang Normal University && IMP-CAS
  \class ETFPlaHit
  \brief for a DC hit, i.e. a fired sense wire.
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-10-29
  \date 2021-11-30 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-10-29   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <iostream>
#include <cstring>
#include <TGraph.h>
#include "ETFPlaHit.h"
#include "ETFHPTDCChannel.h"
#include "ETFMsg.h"

using std::cout;
using std::endl;

ClassImp(ETFPlaHit);

const double ETFPlaHit::VEFF = 1200. / 7.8; // effective light velocity in pla: in mm/ns

ETFPlaHit::ETFPlaHit() : fLength(1200.){ // 1200. for TOFWall strips
  Initialize();
} // end ctor

// copy ctor
ETFPlaHit::ETFPlaHit(const ETFPlaHit &t){
  *this = t;
} // end copy ctor
// assignment ctor
ETFPlaHit &ETFPlaHit::operator=(const ETFPlaHit &t){
  if(&t == this) return *this;

  ETFHit::operator=(t);
  fLength = t.fLength;
  fStripId = t.fStripId;
  fDelay = t.fDelay;
  for(int i = 2; i--;){
    fUCh[i] = t.fUCh[i];
    fDCh[i] = t.fDCh[i];
  } // end for over i

  return *this;
} // end member function operator=

ETFPlaHit::~ETFPlaHit(){}

double ETFPlaHit::GetTime(){
  if(-9999. != fHitTime) return fHitTime;

  if(GetFiredStatus() != 4){
    ETFMsg::Info("ETFPlaHit", "GetTime: not (properly) fired");
    // return -9999.;
  } // end if
  return fHitTime = (fUCh[0]->GetLeadingEdge()+fDCh[0]->GetLeadingEdge())/2. - fDelay;
} // end member function GetTime

// distance to the down end
double ETFPlaHit::GetHitPosition(){
  return GetFiredStatus() >= 2 ? fHitPos : -9999.;
} // end member function GetHitPosition

void ETFPlaHit::Initialize(){
  ETFHit::Initialize();
  fStripId = -1;
  // need not delete memory - has been taken care of somewhere else
  for(int i = 2; i--;){ fUCh[i] = nullptr; fDCh[i] = nullptr; }
  fHitPos = -9999.; fHitTime = -9999.;
} // end member function Initialize

// \param udvh: 0-1-2-3: uv-uh-dv-dh
void ETFPlaHit::SetDataChannel(const ETFHPTDCChannel *ch, int udvh){
  if(!ch) ETFMsg::Error("ETFDCHit", "SetDataChannel: ch is nullptr");
  switch(udvh){
    case 0: fUCh[0] = ch; break; // UV
    case 1: fUCh[1] = ch; break; // UH
    case 2: fDCh[0] = ch; break; // DV
    case 3: fDCh[1] = ch; break; // DH
    default: ETFMsg::Error("ETFDCHit", "SetDataChannel: udvh is not 0~3");
  } // end if
} // end member function SetDataChannel

const ETFHPTDCChannel *ETFPlaHit::GetDataChannel(int udvh) const{
  switch(udvh){
    case 0: return fUCh[0]; // UV
    case 1: return fUCh[1]; // UH
    case 2: return fDCh[0]; // DV
    case 3: return fDCh[1]; // DH
    default: ETFMsg::Error("ETFDCHit", "GetDataChannel: udvh is not 0~3");
  } // end if
  return nullptr; // never gets here, just to suppress compiler warnings
} // end member function ETFPlaHit

// return: 1: singly fired; 3: bothly fired, if hitPos good, then 4
int ETFPlaHit::GetFiredStatus(){
  if(-1 != fFiredStatus) return fFiredStatus;

  double timeU = -9999., timeD = -9999.;
  if(fUCh[0] && fUCh[0]->GetNofLeadingEdges()) timeU = fUCh[0]->GetLeadingEdge();
  if(fDCh[0] && fDCh[0]->GetNofLeadingEdges()) timeD = fDCh[0]->GetLeadingEdge();
  fFiredStatus = (timeU > 0.) + (timeD > 0.);
  if(2 == fFiredStatus){
    fHitPos = (timeD-timeU)*VEFF + fLength/2.; // distance from hit to the D end
    if(fHitPos > -3.*fLength && fHitPos < 3.*fLength) fFiredStatus = 4; // good hit
    else fFiredStatus = 3;
  } // end if

  return fFiredStatus;
} // end member function GetFiredStatus

// time of the upper end
double ETFPlaHit::GetTimeU() const{
  if(!fUCh[0]) ETFMsg::Error("ETFPlaHit", "GetTimeU: data channel not assigned");
  if(!fUCh[0]->GetNofLeadingEdges()) ETFMsg::Error("ETFPlaHit", "GetTimeU: no leading edges found");
  return fUCh[0]->GetLeadingEdge() - fDelay;
} // end member function GetTimeU
// time of the down end
double ETFPlaHit::GetTimeD() const{
  if(!fDCh[0]) ETFMsg::Error("ETFPlaHit", "GetTimeD: data channel not assigned");
  if(!fDCh[0]->GetNofLeadingEdges()) ETFMsg::Error("ETFPlaHit", "GetTimeD: no leading edges found");
  return fDCh[0]->GetLeadingEdge() - fDelay;
} // end member function GetTimeD

void ETFPlaHit::ConfigureDraw(){
  const int sta = GetFiredStatus();
  if(sta <= 0) return;

  ETFHit::ConfigureDraw();
  fGHit->SetMarkerStyle(28);
  if(4 == sta) fGHit->SetMarkerColor(kRed);
  if(2 == sta) fGHit->SetMarkerColor(kCyan);
  if(1 == sta) fGHit->SetMarkerColor(kYellow);
} // end member function ConfigureDraw

// print the hit info
void ETFPlaHit::Print(){
  ETFHit::Print();
  cout << "StripId: " << fStripId << endl;
  cout << "strip length: " << fLength << " v_eff: " << VEFF << "mm/ns" << endl;
  for(int i = 0; i < 2; i++) if(fUCh[i]) fUCh[i]->Print();
  for(int i = 0; i < 2; i++) if(fDCh[i]) fDCh[i]->Print();
  if(4 == fFiredStatus) cout << "hit time: " << fHitTime << " hit pos: " << fHitPos << endl;
} // end member function Print
